﻿using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace ZeroBug.EasyFlow.Core
{
    [Serializable]
    public class Variable : ICloneable
    {
        private object _lockObj = new object();
        private VariableManager? _variableManager;
        private List<string> _values;
        public string? Name { get; set; }
        public string? Group { get; set; }
        public VariableType VariableType { get; set; }
        public string Tag { get; set; }
        public List<string> OriginalValues { get; set; }
        public List<string> LinkedVarNames { get; set; }
        [XmlIgnore]
        public Func<string[]>? GetCurrentValues { get; set; }
        [XmlIgnore]
        public int Count => _values.Count;
        [XmlIgnore]
        public Action? NotifyVariableChanged { get; set; }
        public Variable()
        {
            _values = new List<string>();
            OriginalValues = new List<string>();
            Name = "";
            Group = "";
            Tag = "";
            OriginalValues = new List<string>();
            LinkedVarNames = new List<string>();
        }
        public Variable(string name)
            : this()
        {
            Name = name;
        }
        public Variable(string name, string value, VariableType varType)
            : this(name)
        {
            this.VariableType = varType;
            lock (_lockObj)
            {
                _values = new List<string>();
                _values.Add(value);
                OriginalValues = new List<string>();
                OriginalValues.Add(value);
            }
        }
        public Variable(string name, string[] values, VariableType varType)
            : this(name)
        {
            this.VariableType = varType;
            if (values == null)
                return;
            lock (_lockObj)
            {
                _values = new List<string>();
                OriginalValues = new List<string>();
                for (int i = 0; i < values.Length; i++)
                {
                    _values.Add(values[i]);
                    OriginalValues.Add(values[i]);
                }
            }
        }
        public Variable(string name, List<Variable> vars, VariableType varType)
            : this(name) 
        {
            this.VariableType = varType;
            if (vars == null || vars.Count == 0)
                return;
            lock (_lockObj)
            {
                LinkedVarNames = vars.Select(v => v.Name).ToList()!;
            }
        }
        private void update(string[]? newValues)
        {
            if (newValues == null) return;
            lock (_lockObj)
            {
                _values = new List<string>();
                for (int i = 0; i < newValues.Length; i++)
                {
                    _values.Add(newValues[i]);
                }
            }
        }
        public string this[int index]
        {
            get
            {
                if (LinkedVarNames != null && LinkedVarNames.Count > 0)
                {
                    GetCurrentValues = () => LinkedVarNames.Select(vn => _variableManager.GetVariable(vn)[0]).ToArray();
                }
                update(GetCurrentValues?.Invoke());
                if (index >= 0 && index < _values.Count)
                {
                    return _values[index];
                }
                else
                    throw new IndexOutOfRangeException("Index out of range");
            }
            set
            {
                if (index >= 0 && index < _values.Count)
                {
                    lock (_lockObj)
                    {
                        _values[index] = value;
                    }
                    NotifyVariableChanged?.Invoke();
                }
                else
                    throw new IndexOutOfRangeException("Index out of range");
            }
        }
        public override string ToString()
        {
            update(GetCurrentValues?.Invoke());
            return $"{string.Join(",", _values)}";
        }
        public int IndexOf(string item)
        {
            return _values.IndexOf(item);
        }
        public bool Any(Predicate<string> predicate)
        {
            foreach (string item in _values)
            {
                if (predicate(item))
                    return true;
            }
            return false;
        }
        public void Add(string item)
        {
            lock (_lockObj)
            {
                if (_values == null)
                    _values = new List<string>();
                _values.Add(item);
            }
            NotifyVariableChanged?.Invoke();
        }
        public void Reset()
        {
            if (OriginalValues != null && OriginalValues.Count > 0)
            {
                lock (_lockObj)
                {
                    _values.Clear();
                    for (int i = 0; i < OriginalValues.Count; i++)
                    {
                        _values.Add(OriginalValues[i]);
                    }
                }
                NotifyVariableChanged?.Invoke();
            }
        }
        public void SetVariableManager(VariableManager variableManager)
        {
            this._variableManager = variableManager;
        }
        public bool CompareTo(CompareSign sign, Variable varB, int compareIndex)
        {
            switch(sign)
            {
                case CompareSign.等于:
                    return this[compareIndex].ToLower().Equals(varB[compareIndex].ToLower());
                case CompareSign.不等于:
                    return !this[compareIndex].ToLower().Equals(varB[compareIndex].ToLower());
                case CompareSign.大于:
                    if (this.VariableType != VariableType.Numeric ||
                        varB.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) > Convert.ToDouble(varB[compareIndex]);
                case CompareSign.小于:
                    if (this.VariableType != VariableType.Numeric ||
                        varB.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) < Convert.ToDouble(varB[compareIndex]);
                case CompareSign.大于等于:
                    if (this.VariableType != VariableType.Numeric ||
                        varB.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) >= Convert.ToDouble(varB[compareIndex]);
                case CompareSign.小于等于:
                    if (this.VariableType != VariableType.Numeric ||
                        varB.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) <= Convert.ToDouble(varB[compareIndex]);
                case CompareSign.与:
                    if (this.VariableType != VariableType.Boolean ||
                        varB.VariableType != VariableType.Boolean)
                        throw new Exception("比较的变量必须为逻辑变量!");
                    return Convert.ToBoolean(this[compareIndex]) && Convert.ToBoolean(varB[compareIndex]);
                case CompareSign.或:
                    if (this.VariableType != VariableType.Boolean ||
                        varB.VariableType != VariableType.Boolean)
                        throw new Exception("比较的变量必须为逻辑变量!");
                    return Convert.ToBoolean(this[compareIndex]) || Convert.ToBoolean(varB[compareIndex]);
            }
            return false;
        }
        public bool CompareTo(CompareSign sign, string varB, int compareIndex)
        {
            switch (sign)
            {
                case CompareSign.等于:
                    return this[compareIndex].ToLower().Equals(varB.ToLower());
                case CompareSign.大于:
                    if (this.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) > Convert.ToDouble(varB);
                case CompareSign.小于:
                    if (this.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) < Convert.ToDouble(varB);
                case CompareSign.大于等于:
                    if (this.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) >= Convert.ToDouble(varB);
                case CompareSign.小于等于:
                    if (this.VariableType != VariableType.Numeric)
                        throw new Exception("比较的变量必须为数值型!");
                    return Convert.ToDouble(this[compareIndex]) <= Convert.ToDouble(varB);
                case CompareSign.与:
                    if (this.VariableType != VariableType.Boolean)
                        throw new Exception("比较的变量必须为逻辑变量!");
                    return Convert.ToBoolean(this[compareIndex]) && Convert.ToBoolean(varB);
                case CompareSign.或:
                    if (this.VariableType != VariableType.Boolean)
                        throw new Exception("比较的变量必须为逻辑变量!");
                    return Convert.ToBoolean(this[compareIndex]) || Convert.ToBoolean(varB);
            }
            return false;
        }
        public bool IsEmpty()
        {
            return _values == null || _values.Count == 0;
        }
        public object Clone()
        {
            return MemberwiseClone();
        }
        public void LoadFromOriginalValue()
        {
            update(OriginalValues.ToArray());
        }
    }
    public enum VariableFrom
    {
        [Description("自定义")]
        Define,
        [Description("函数")]
        Function,
        [Description("本流程")]
        Local,
        [Description("全局")]
        Global,
        [Description("配方")]
        Recipe,
        [Description("资源")]
        Resource,
    }
    public enum VariableType
    {
        //默认文本变量
        [Description("文本变量")]
        Text,
        [Description("数值变量")]
        Numeric,
        [Description("判断变量")]
        Boolean
    }
    public enum CompareSign
    {
        [Description("=")]
        等于,
        [Description("!=")]
        不等于,
        [Description(">")]
        大于,
        [Description("<")]
        小于,
        [Description(">=")]
        大于等于,
        [Description("<=")]
        小于等于,
        [Description("&&")]
        与,
        [Description("||")]
        或,
    }
}
